package script

import (
	"fmt"
	"math"
	"path/filepath"
	"sync"
	"tinyGW/app/models"
	"tinyGW/pkg/plugin/io"

	"go.uber.org/fx"

	"github.com/yuin/gluamapper"
	lua "github.com/yuin/gopher-lua"
	"go.uber.org/zap"
)

type (
	Runner interface {
		Open(filename string) error
		Close()
		GenerateGetRealVariables(address string, step int) (data []byte, result bool, continued bool)
		DeviceCustomCmd(sAddr string, cmdName string, cmdParam string, step int) ([]byte, bool, bool)
		AnalysisRx(sAddr string, variables []models.DeviceProperty, rxBuf []byte, rxBufCnt int, tempVariables *[]models.DeviceProperty) bool
	}

	luaRunner struct {
		lState     *lua.LState
		filename   string
		isValid    bool
		mutex      sync.RWMutex
		bufferPool sync.Pool // 字节缓冲池
	}

	// LuaResult 统一的Lua调用结果结构
	LuaResult struct {
		Status   string  `json:"Status"`
		Variable []*byte `json:"Variable"`
	}

	// LuaVariable Lua变量模板
	LuaVariable struct {
		Index   int         `json:"Index"`
		Name    string      `json:"Name"`
		Label   string      `json:"Label"`
		Type    string      `json:"Type"`
		Value   interface{} `json:"Value"`
		Explain string      `json:"Explain"`
	}

	// LuaVariableMap Lua变量映射模板
	LuaVariableMap struct {
		Status   string         `json:"Status"`
		Variable []*LuaVariable `json:"Variable"`
	}
)

func NewLuaRunner() Runner {
	return &luaRunner{
		lState:  nil,
		isValid: false,
		bufferPool: sync.Pool{
			New: func() interface{} {
				return make([]byte, 0, 256) // 预分配256字节容量
			},
		},
	}
}

func (l *luaRunner) Open(filename string) error {
	l.mutex.Lock()
	defer l.mutex.Unlock()

	// 如果已经打开了相同的文件，直接返回
	if l.lState != nil && l.filename == filename && l.isValid {
		return nil
	}

	// 关闭旧的状态
	if l.lState != nil {
		l.lState.Close()
	}

	// 创建新的Lua状态
	l.lState = lua.NewState()
	l.filename = filename
	l.isValid = false

	// 构建脚本路径
	path := filepath.Join(io.GetCurrentPath(), "plugin", filename, filename+".lua")

	// 加载脚本文件
	if err := l.lState.DoFile(path); err != nil {
		zap.S().Errorf("Failed to load Lua script: %v, path: %s", err, path)
		l.lState.Close()
		l.lState = nil
		return err
	}

	// 注册全局函数
	l.registerGlobalFunctions()
	l.isValid = true

	return nil
}

func (l *luaRunner) Close() {
	l.mutex.Lock()
	defer l.mutex.Unlock()

	if l.lState != nil {
		l.lState.Close()
		l.lState = nil
	}
	l.isValid = false
	l.filename = ""
}

// registerGlobalFunctions 注册全局函数
func (l *luaRunner) registerGlobalFunctions() {
	l.lState.SetGlobal("GetCRCModbus", l.lState.NewFunction(GetCRCModbus))
	l.lState.SetGlobal("CheckCRCModbus", l.lState.NewFunction(CheckCRCModbus))
	l.lState.SetGlobal("GetCRCModbusLittleEndian", l.lState.NewFunction(GetCRCModbusLittleEndian))
}

// isStateValid 检查Lua状态是否有效
func (l *luaRunner) isStateValid() bool {
	l.mutex.RLock()
	defer l.mutex.RUnlock()
	return l.lState != nil && l.isValid
}

// callLuaFunction 统一的Lua函数调用方法
func (l *luaRunner) callLuaFunction(funcName string, args ...lua.LValue) (*lua.LTable, error) {
	if !l.isStateValid() {
		return nil, fmt.Errorf("lua state is not valid")
	}

	l.mutex.RLock()
	defer l.mutex.RUnlock()

	// 调用Lua函数
	if err := l.lState.CallByParam(lua.P{
		Fn:      l.lState.GetGlobal(funcName),
		NRet:    1,
		Protect: true,
	}, args...); err != nil {
		return nil, fmt.Errorf("call %s failed: %v", funcName, err)
	}

	// 获取返回结果
	ret := l.lState.Get(-1)
	l.lState.Pop(1)

	if table, ok := ret.(*lua.LTable); ok {
		return table, nil
	}

	return nil, fmt.Errorf("unexpected return type from %s", funcName)
}

// extractByteArrayFromResult 从结果中提取字节数组
func (l *luaRunner) extractByteArrayFromResult(table *lua.LTable) ([]byte, bool) {
	result := LuaResult{}
	if err := gluamapper.Map(table, &result); err != nil {
		zap.S().Errorf("Failed to map result: %v", err)
		return nil, false
	}

	// 使用缓冲池获取字节切片
	buffer := l.bufferPool.Get().([]byte)
	buffer = buffer[:0] // 重置长度但保持容量

	// 将结果复制到缓冲区
	for _, v := range result.Variable {
		if v != nil {
			buffer = append(buffer, *v)
		}
	}

	// 创建最终的字节切片
	data := make([]byte, len(buffer))
	copy(data, buffer)

	// 归还缓冲区到池中
	l.bufferPool.Put(buffer)

	return data, result.Status != "0"
}

func (l *luaRunner) GenerateGetRealVariables(address string, step int) ([]byte, bool, bool) {
	table, err := l.callLuaFunction("GenerateGetRealVariables",
		lua.LString(address),
		lua.LNumber(step))

	if err != nil {
		zap.S().Errorf("GenerateGetRealVariables error: %v", err)
		return nil, false, false
	}

	data, continued := l.extractByteArrayFromResult(table)
	return data, len(data) > 0, continued
}

func (l *luaRunner) DeviceCustomCmd(address string, commandName string, commandParam string, step int) ([]byte, bool, bool) {
	table, err := l.callLuaFunction("DeviceCustomCmd",
		lua.LString(address),
		lua.LString(commandName),
		lua.LString(commandParam),
		lua.LNumber(step))

	if err != nil {
		zap.S().Errorf("DeviceCustomCmd error: %v", err)
		return nil, false, false
	}

	data, continued := l.extractByteArrayFromResult(table)
	return data, len(data) > 0, continued
}

// convertLuaValueToGo 优化的类型转换函数
func (l *luaRunner) convertLuaValueToGo(luaValue interface{}, targetType string, scale float64, decimal int) interface{} {
	if luaValue == nil {
		switch targetType {
		case "string":
			return ""
		default:
			return float64(0)
		}
	}

	// 应用倍率
	if scale > 0 && scale != 1 {
		if val, ok := luaValue.(float64); ok {
			luaValue = val * scale
		}
	}

	switch targetType {
	case "int":
		if val, ok := luaValue.(float64); ok {
			return int32(val)
		}
	case "uint":
		if val, ok := luaValue.(float64); ok {
			return uint32(val)
		}
	case "double":
		if val, ok := luaValue.(float64); ok {
			return val / math.Pow10(decimal)
		}
	case "string":
		if val, ok := luaValue.(string); ok {
			return val
		}
	}

	return luaValue
}

func (l *luaRunner) AnalysisRx(sAddr string, variables []models.DeviceProperty, rxBuf []byte, rxBufCnt int, tempVariables *[]models.DeviceProperty) bool {
	if !l.isStateValid() {
		return false
	}

	l.mutex.RLock()
	defer l.mutex.RUnlock()

	// 创建Lua表并设置全局变量 - 优化内存分配
	table := &lua.LTable{}
	table.RawSet(lua.LNumber(0), lua.LNil) // 预分配

	for i, v := range rxBuf {
		table.RawSetInt(i+1, lua.LNumber(v))
	}
	l.lState.SetGlobal("rxBuf", table)

	// 调用AnalysisRx
	err := l.lState.CallByParam(lua.P{
		Fn:      l.lState.GetGlobal("AnalysisRx"),
		NRet:    1,
		Protect: true,
	}, lua.LString(sAddr), lua.LNumber(rxBufCnt))

	if err != nil {
		zap.S().Warnf("AnalysisRx error: %v", err)
		return false
	}

	// 获取返回结果
	ret := l.lState.Get(-1)
	if ret == nil {
		return false
	}
	l.lState.Pop(1)

	// 解析结果
	luaVariableMap := LuaVariableMap{}
	if err := gluamapper.Map(ret.(*lua.LTable), &luaVariableMap); err != nil {
		zap.S().Warnf("AnalysisRx mapping error: %v", err)
		return false
	}

	if luaVariableMap.Status != "0" {
		return false
	}

	// 处理变量 - 优化查找逻辑
	variableMap := make(map[string]*models.DeviceProperty, len(variables))
	for i := range variables {
		variableMap[variables[i].Name] = &variables[i]
	}

	// 预分配临时变量切片
	if cap(*tempVariables) < len(luaVariableMap.Variable) {
		*tempVariables = make([]models.DeviceProperty, 0, len(luaVariableMap.Variable))
	} else {
		*tempVariables = (*tempVariables)[:0]
	}

	for _, lv := range luaVariableMap.Variable {
		if prop, exists := variableMap[lv.Name]; exists {
			// 使用优化的类型转换
			convertedValue := l.convertLuaValueToGo(lv.Value, prop.Type, prop.Scale, prop.Decimal)
			prop.Value = convertedValue

			// 添加到临时变量表中
			*tempVariables = append(*tempVariables, *prop)
		}
	}

	return true
}

var Module = fx.Provide(
	NewLuaRunner,
)
